package com.gzxx.util;

import com.redisdatastorage.config.RedisProperties;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;

import java.util.Collections;

/**
 * RedisLock
 *
 * @author chenjing
 */
@Slf4j
@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class RedisLock {

    private final RedisProperties redisProperties;

    private static final String LOCK_SUCCESS = "OK";
    private static final String SET_IF_NOT_EXIST = "NX";
    private static final String SET_WITH_EXPIRE_TIME = "PX";

    private static final Object lock = new Object();
    private static volatile Jedis jedis;

    /**
     * 实例化
     */
    public static Jedis instantiation(RedisProperties properties) {
        if (jedis == null) {
            synchronized (lock) {
                if (jedis == null) {
                    jedis = new Jedis(properties.getHost(), properties.getPort());
                    //带密码需要执行认证方法
                    if (StringUtils.isNotEmpty(properties.getPassword())) {
                        jedis.auth(properties.getPassword());
                    }
                }
            }
        }
        return jedis;
    }

    /**
     * 加锁
     *
     * @param lockKey
     * @param expireTime 单位秒
     * @return
     */
    public boolean lock(String lockKey, String value, int expireTime) {
        String result = instantiation(redisProperties).set(lockKey, value, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime * 1000);
        if (LOCK_SUCCESS.equals(result)) {
            log.info("lockKey:{} 获取锁成功 用户：{}", lockKey, value);
            return true;
        }
        log.info("lockKey:{} 获取锁失败 用户：{}", lockKey, value);
        return false;
    }

    /**
     * 解锁
     */
    public boolean unlock(String key, String value) {
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        Object result = instantiation(redisProperties).eval(script, Collections.singletonList(key), Collections.singletonList(value));
        if (result.equals(1L)) {
            log.info("lockKey:{} 释放锁成功 用户：{}", key, value);
            return true;
        }
        log.info("lockKey:{} 释放锁失败 用户：{}", key, value);
        return false;
    }

}
